﻿using G19Glower.Shared;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace G19Glower.App
{
    /// <summary>
    /// LOL! Hooker means prostitute.
    /// </summary>
    internal class KeyboardHooker : IKeyboardListener
    {
        private LowLevelKeyboardHandler mKeyEventHandler;
        private IntPtr mHookID = IntPtr.Zero;

        internal event Action<Keys> KeyPressed;

        #region .ctor

        internal KeyboardHooker()
        {
            mKeyEventHandler = this.HookCallback;
        }

        #endregion

        #region Main Methods

        internal void SetHook()
        {
            if (mHookID != IntPtr.Zero)
            {
                throw new InvalidOperationException();
            }

            using (Process curProcess = Process.GetCurrentProcess())
            {
                using (ProcessModule curModule = curProcess.MainModule)
                {
                    mHookID = SetWindowsHookEx(WH_KEYBOARD_LL, mKeyEventHandler, GetModuleHandle(curModule.ModuleName), 0);
                }
            }
        }

        internal void UnsetHook()
        {
            if (mHookID == IntPtr.Zero)
            {
                throw new InvalidOperationException();
            }

            UnhookWindowsHookEx(mHookID);

            mHookID = IntPtr.Zero;
        }

        #endregion

        #region Handlers

        private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                Console.WriteLine((Keys)vkCode);
                if (KeyPressed != null)
                {
                    KeyPressed((Keys)vkCode);
                }
            }

            return CallNextHookEx(mHookID, nCode, wParam, lParam);
        }

        #endregion

        #region IKeyboardListener Members

        event Action<Keys> IKeyboardListener.KeyPressed
        {
            add { KeyPressed += value; }
            remove { KeyPressed -= value; }
        }

        #endregion

        #region Old School

        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;

        private delegate IntPtr LowLevelKeyboardHandler(int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,LowLevelKeyboardHandler lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        #endregion
    }
}
